package controller

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"

	"gitee.com/liuyun-luo/MagicStreamMovies/Server/config"
	"gitee.com/liuyun-luo/MagicStreamMovies/Server/global"
	"gitee.com/liuyun-luo/MagicStreamMovies/Server/llm"
	"gitee.com/liuyun-luo/MagicStreamMovies/Server/models"
	"gitee.com/liuyun-luo/MagicStreamMovies/Server/search"
	"gitee.com/liuyun-luo/MagicStreamMovies/Server/utils"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

// 基于AI为用户推荐电影
func AIRecommendMovies(ctx *gin.Context) {
	user_id := ctx.Param("user_id")
	if user_id == "" {
		ctx.JSON(400, gin.H{
			"error": "参数错误,user_id不能为空",
		})
		return
	}

	var inputDTO struct {
		Message string `json:"message" binding:"required,min=10"`
	}

	if err := ctx.ShouldBindJSON(&inputDTO); err != nil {
		ctx.JSON(400, gin.H{
			"error": "参数错误,err: " + err.Error(),
		})
		return
	}

	//AI返回的结果电影类型的格式
	type genreResultFormat struct {
		Id        uint   `json:"id"`
		GenreName string `json:"genre_name"`
	}

	//构建发送给AI的消息
	message := map[string]any{
		"user_message":         inputDTO.Message,
		"all_movie_genre_list": config.AllMovieGenre,
		"result_format":        "id(uint),genre_name(string)",
		"system_message":       "请根据message字段中的内容(内容为用户想要看的电影的描述)，判断用户想看的电影类型是哪些。所有支持的电影类型id与电影类型的名字都放在了all_movie_genre_list字段中，请你根据支持的电影类型进行判断，并把结果按照result_format字段中的json形式返回(如果喜欢类型不止一个，就返回一个数组),不需要返回任何额外内容",
		"prompt":               config.AIBasePrompt,
	}

	message_json, err := json.MarshalIndent(message, "", " ")
	if err != nil {
		ctx.JSON(500, gin.H{
			"error": "json序列化失败" + err.Error(),
		})
		return
	}

	// 把提示词喂给AI，获得用户想看的电影的具体类型是什么
	result_json, err := llm.GetMessageFromAI(string(message_json), ctx)
	if err != nil {
		ctx.JSON(500, gin.H{
			"error": "AI调用失败,err: " + err.Error(),
		})
		return
	}

	//反序列化结果
	var genre_result_list []genreResultFormat
	if err := json.Unmarshal([]byte(result_json), &genre_result_list); err != nil {
		ctx.JSON(500, gin.H{
			"error": "json反序列化失败" + err.Error(),
		})
		return
	}

	fmt.Println(genre_result_list)

	AI_c := make(chan string)
	AI_c_err := make(chan error)

	go func() {
		//构建发送给AI的消息
		message := map[string]any{
			"user_message":         inputDTO.Message,
			"all_movie_genre_list": config.AllMovieGenre,
			"result_format":        "[most_consistent_movie_names]([]string),[consistent_movie_names]([]string),[possibly_consistent_movie_names]([]string)",
			"system_message":       "请你根据用户的输入的内容，全网搜索，判断用户想看的电影是具体是什么，至少找到50部电影。并按照符合的程度，把电影的名字填入不同的数组中，即结果为一个json序列化后的string切片，不需要返回任何额外内容",
			"prompt":               config.AIBasePrompt,
		}

		message_json, err := json.MarshalIndent(message, "", " ")
		if err != nil {
			AI_c <- ""
			AI_c_err <- errors.New("json序列化失败" + err.Error())
			return
		}

		//获取AI全网搜索用户描述之后，用户想看的电影的名字具体是什么
		result_json, err := llm.GetMessageFromAI(string(message_json), ctx)
		if err != nil {
			AI_c <- ""
			AI_c_err <- errors.New("AI调用失败,err: " + err.Error())
			return
		}

		//返回结果
		AI_c <- result_json
		AI_c_err <- nil
	}()

	//分类筛选，并按照评分降序，取出前10部电影
	query := global.MySQLDb.Model(&models.Movie{})

	var ids []uint
	for index := range genre_result_list {
		ids = append(ids, genre_result_list[index].Id)
	}
	//添加筛选条件
	query = utils.FilterMovie(query, ids)

	var rating_movie_list []models.Movie

	//执行查询
	if err := query.Order("rating desc").Limit(10).Find(&rating_movie_list).Error; err != nil {
		ctx.JSON(500, gin.H{
			"error": "数据库查询失败" + err.Error(),
		})
		return
	}

	//取出排行榜中，热度前50的电影
	zset := utils.NewMoviesPopularityZSet(global.RedisDB, config.MoviesPopularityZSetKeyName)

	var popularity_movies []models.Movie

	popularity_movie_ids, _, err := zset.GetRange(0, 50)
	if err != nil {
		log.Printf("Redis查询失败,keyname: %s,err: %s", zset.Name, err.Error())
	} else {
		que := global.MySQLDb.Model(&models.Movie{})
		//分类电影
		que = utils.FilterMovie(que, ids)

		if err := que.Where("movies.id IN ?", popularity_movie_ids).Find(&popularity_movies).Error; err != nil {
			ctx.JSON(500, gin.H{
				"error": "MySQL查询失败" + err.Error(),
			})
			return
		}
	}

	//获取AI全网搜索之后，推荐的电影的名字
	AI_movie_name_list_result := <-AI_c
	err = <-AI_c_err
	if err != nil {
		ctx.JSON(500, gin.H{
			"error": "AI处理失败" + err.Error(),
		})
		return
	}
	var send_search search.AIRecommendSearchRequest

	if err := json.Unmarshal([]byte(AI_movie_name_list_result), &send_search); err != nil {
		ctx.JSON(500, gin.H{
			"error": "AI处理返回的结果格式不正确" + err.Error(),
		})
		return
	}

	//发送给搜索引擎
	search_movies, err := search.SearchAIRecommendMovie(ctx, send_search)
	if err != nil {
		ctx.JSON(500, gin.H{
			"error": "搜索引擎处理失败" + err.Error(),
		})
		return
	}

	var response_movie_ids []uint
	if len(search_movies.MostConsistentMovieIds) > 0 {
		if len(search_movies.MostConsistentMovieIds) > 3 {
			response_movie_ids = search_movies.MostConsistentMovieIds[:3]
		} else {
			response_movie_ids = search_movies.MostConsistentMovieIds
		}
	} else if len(search_movies.ConsistentMovieIds) > 0 {
		if len(search_movies.ConsistentMovieIds) > 3 {
			response_movie_ids = search_movies.ConsistentMovieIds[:3]
		} else {
			response_movie_ids = search_movies.ConsistentMovieIds
		}
	} else if len(search_movies.PossiblyConsistentMovieIds) > 0 {
		if len(search_movies.PossiblyConsistentMovieIds) > 3 {
			response_movie_ids = search_movies.PossiblyConsistentMovieIds[:3]
		} else {
			response_movie_ids = search_movies.PossiblyConsistentMovieIds
		}
	} else { //没有找到相关电影
		//再次投喂AI
		if len(popularity_movies) > 0 {
		}
	}

	var response []models.Movie
	if err := global.MySQLDb.Where("id IN ?", response_movie_ids).Preload("GenreList").Preload("MovieSynopsis").Find(&response).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) { //如果错误类型为：找不到资源类型的错误
			log.Println("搜索引擎搜索到的结果数据库中没有" + err.Error())
			ctx.JSON(404, gin.H{
				"error": "搜索引擎搜索到的结果数据库中没有" + err.Error(),
			})
		} else {
			ctx.JSON(500, gin.H{
				"error": "数据库查询失败" + err.Error(),
			})
		}
	}
	ctx.JSON(200, gin.H{
		"recommend_movie_list": response,
	})
}
